package com.sun.aop;

import com.sun.annotation.RepeatSubmit;
import com.sun.utils.RedisCacheTemplate;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


/**
 * 这个是通过拦截器的方式进行防止接口的重复提交
 * 也可以使用AOP的方式进行防止接口的重复提交
 */
@Component
@Aspect
@Slf4j
public class RepeatSubmitAop {

    @Autowired
    private RedisCacheTemplate redisCacheTemplate;

    @Pointcut("@annotation(com.sun.annotation.RepeatSubmit)")
    public void submit() {
    }


    @Around("submit()")
    public String noRepeatSubmit(ProceedingJoinPoint joinPoint) {
        try {
            //获取类的字节码对象
            Class<?> targetClass = joinPoint.getTarget().getClass();
            //获取方法签名(通过此签名获取目标方法信息)
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获取目标方法上的注解指定的操作名称
            Method method = targetClass.getDeclaredMethod(signature.getName(), signature.getParameterTypes());
            //获取指定注解
            RepeatSubmit repeatSubmit = method.getAnnotation(RepeatSubmit.class);
            //有效时间
            int interval = repeatSubmit.interval();
            //提示信息
            String message = repeatSubmit.message();

            //生成一个唯一的key存储在redis中
            String methodName = signature.getName();
            //获取类名
            String className = targetClass.getName();

            String key = className + ":" + methodName;
            //查看key是否存在
            Boolean flag = redisCacheTemplate.exists(key);
            if (!flag) {
                try {
                    //不存在
                    redisCacheTemplate.setCacheObject(key, UUID.randomUUID().toString().substring(5), interval, TimeUnit.SECONDS);
                    return (String) joinPoint.proceed();
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                }
            }
            return message;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return "";
    }
}
